import requests
import json
import base64
import hmac
import hashlib
import time
from urllib.parse import urlencode
from ..exceptions import PlatformAPIException, PlatformRequestException, PlatformClientException
from ..restapibase import RestAPIBase

from MarketData.const import CONST


class BittrexRESTAPI(RestAPIBase):
    """docstring for BitfinexRESTAPI"""

    def __init__(self, api_key, secret_key, isdebug=False):
        self.api_key = api_key
        self.api_secret = secret_key
        self.isdebug = isdebug
        self.url = 'https://bittrex.com/api/v1.1'

    def _debug(self, result):
        if self.isdebug:
            print(result)

    def _get_auth(self, url, data):

        payload = url

        if data:
            payload += '&' + urlencode(data)

        signature = hmac.new(self.api_secret.encode('utf-8'), payload.encode('utf-8'), hashlib.sha512).hexdigest()

        self._debug('payload: %s, signature: %s \n' % (payload, signature))

        headers = {
            'apisign': signature
        }

        return headers

    def _get(self, endpoint, params={}):
        nonce = str(int(time.time() * 1000))
        url = "{0}?apikey={1}&nonce={2}".format(self.url + endpoint, self.api_key, nonce)

        headers = self._get_auth(url, params)

        response = requests.get(url, headers=headers, params=params)
        # self._debug(response.text)

        errmsg = 'StatusCode: GET %s \nURL:%s \nParams: %s \nResponse: %s' % (response.status_code, url, str(params), response.text)
        response = response.json()

        if response:
            if response['success'] is True:
                return response
            else:
                raise PlatformAPIException(errmsg)
        else:
            raise PlatformRequestException(errmsg)

    def _post(self, endpoint, data={}):
        nonce = str(int(time.time() * 1000))
        url = "{0}?apikey={1}&nonce={2}".format(self.url + endpoint, self.api_key, nonce)

        self._debug(url)

        headers = self._get_auth(url, data)
        response = requests.post(url, headers=headers, params=data)

        errmsg = 'StatusCode: POST %s \nURL:%s \nData: %s \nResponse: %s' % (response.status_code, url, str(data), response.text)
        response = response.json()

        if response:
            if response['success'] is True:
                return response
            else:
                raise PlatformAPIException(errmsg)
        else:
            raise PlatformRequestException(errmsg)

    # EndPoints
    def _markets(self):
        url = '/public/getmarkets'
        result = self._get(url)
        self._debug('markets: \n' + json.dumps(result, indent=2))
        return result

    def _currency_pair(self):
        url = '/public/getcurrencies'
        result = self._get(url)
        self._debug('currency_pair: \n' + json.dumps(result, indent=2))
        return result

    # Public
    def get_currency(self, currency):
        return currency.upper()

    def get_symbol(self, commodity, base):
        '''[summary]

        [description]

        Arguments:
            src {[string]} -- [description]
            dest {[string]} -- [description]

        Raises:
            NotImplementedError -- [description]
        '''
        return base.upper() + '-' + commodity.upper()

    def get_ticker(self, symbol):
        '''[summary]

        [description]

        Arguments:
            symbol {[type]} -- [description]

        Returns:
            [type] -- [{
                  "mid": "0.029707",
                  "ask": "0.029728",
                  "volume": "263353.6641857",
                  "high": "0.036467",
                  "low": "0.029049",
                  "bid": "0.029686",
                  "last_price": "0.02972",
                  "timestamp": "1512632242.711332"
                }]
        '''
        url = '/public/getticker'

        params = {
            'market': symbol,
        }
        result = self._get(url, params)
        self._debug('ticker: \n' + json.dumps(result, indent=2))
        return result

    def get_depth(self, symbol):
        '''
        [description]

        Arguments:
            symbol {[type]} -- [description]

        Returns:
            {
              "bids": [
                {
                  "price": "0.029678",
                  "amount": "22.88434254",
                  "timestamp": "1512632248.0"
                }],
                "asks": [
                    {
                      "price": "0.029739",
                      "amount": "1.0035",
                      "timestamp": "1512632248.0"
                }]
            }
        '''
        url = '/public/getorderbook'
        params = {
            'market': symbol,
            'type': 'both',
        }
        resjson = self._get(url, params)

        bids = []
        asks = []
        result = {}

        self._debug('order_book: \n' + json.dumps(resjson, indent=2))

        for bid in resjson['result']['buy']:
            bids.append({'price': bid['Rate'], 'amount': bid['Quantity']})

        for ask in resjson['result']['sell']:
            asks.append({'price': ask['Rate'], 'amount': ask['Quantity']})

        #asks.reverse()

        result = {'bids': bids, 'asks': asks}

        self._debug('order_book: \n' + json.dumps(result, indent=2))
        return result

    def get_account(self):
        raise NotImplementedError()

    def get_balances(self, type='trade'):
        url = '/account/getbalances'

        resjson = self._get(url)
        result = {}
        for balance in resjson['result']:
            result[balance['Currency']] = balance['Available']

        self._debug('[GET] account: \n' + json.dumps(result, indent=2))
        return result

    def limit_buy(self, symbol, amount, price):
        '''[summary]

        [description]

        Arguments:
            symbol {[type]} -- [description]
            amount {[type]} -- [description]
            price {[type]} -- [description]

        Returns:
            [type] -- [description]
        '''
        url = '/market/buylimit'
        data = {
            'market': symbol,
            'quantity': amount,
            'rate': price
        }

        resjson = self._post(url, data)
        result = {'order_id': resjson['result']['uuid']}
        self._debug('[get] limit_buy: \n' + json.dumps(result, indent=2))
        return result

    def limit_sell(self, symbol, amount, price):
        '''[summary]

        [description]

        Arguments:
            symbol {[type]} -- [description]
            amount {[type]} -- [description]
            price {[type]} -- [description]

        Returns:
            [type] -- [description]
        '''
        url = '/market/selllimit'
        data = {
            'market': symbol,
            'quantity': amount,
            'rate': price
        }

        resjson = self._post(url, data)
        result = {'order_id': resjson['result']['uuid']}
        self._debug('[get] limit_sell: \n' + json.dumps(result, indent=2))
        return result

    def market_buy(self, symbol, amount, price):
        '''[summary]

        [description]

        Arguments:
            symbol {[type]} -- [description]
            amount {[type]} -- [description]
            price {[type]} -- [description]

        Returns:
            [type] -- [description]
        '''
        url = '/market/buylimit'
        data = {
            'market': symbol,
            'quantity': amount,
            'rate': "%.7f" % (float(price) * (1 + CONST.Slippage_synMarket))
        }

        resjson = self._post(url, data)
        result = {'order_id': resjson['result']['uuid']}
        self._debug('[get] limit_buy: \n' + json.dumps(result, indent=2))
        return result

    def market_sell(self, symbol, amount, price):
        '''[summary]

        [description]

        Arguments:
            symbol {[type]} -- [description]
            amount {[type]} -- [description]
            price {[type]} -- [description]

        Returns:
            [type] -- [description]
        '''
        url = '/market/selllimit'
        data = {
            'market': symbol,
            'quantity': amount,
            'rate': "%.7f" % (float(price) * (1 - CONST.Slippage_synMarket))
        }

        resjson = self._post(url, data)
        result = {'order_id': resjson['result']['uuid']}
        self._debug('[get] limit_sell: \n' + json.dumps(result, indent=2))
        return result

    def get_order(self, symbol, order_id):
        '''[summary]

        [description]

        Arguments:
            symbol {[type]} -- [description]
            order_id {[type]} -- [description]

        Returns:
            [type] -- [description]
        '''
        url = '/account/getorder'
        params = {
            'uuid': order_id,
        }

        result = self._get(url, params)

        self._debug('[get] get_order: \n' + json.dumps(result, indent=2))

    def get_all_orders(self):
        '''[summary]

        [description]

        Arguments:
            symbol {[type]} -- [description]

        Returns:
            [type] -- [description]
        '''
        raise NotImplementedError()

    def get_open_orders(self):
        '''[summary]

        [description]

        Arguments:
            symbol {[string]} -- [ETH]
        '''
        url = '/market/getopenorders'

        result = self._get(url)
        self._debug('[GET] get_open_orders: \n' + json.dumps(result, indent=2))
        return result['result']

    def cancel_order(self, order_id):
        '''[summary]

        [description]

        Arguments:
            symbol {[type]} -- [description]
            order_id {[type]} -- [description]

        Returns:
            [type] -- [description]
        '''
        url = '/market/cancel'
        params = {
            'uuid': order_id,
        }

        result = self._get(url, params)

        self._debug('[get] cancel_order: \n' + json.dumps(result, indent=2))

        return result

    def cancel_all_orders(self):
        result = []
        orders = self.get_open_orders()
        for order in orders:
            result.append(self.cancel_order(order_id=order['OrderUuid']))
        return result

    def withdraw(self, currency, amount, address):
        '''[summary]

        [description]

        Arguments:
            currency {[type]} -- ['bitcoin', 'litecoin', 'ethereum', 'ethereumc', 'mastercoin', 'zcash', 'monero', 'wire', 'dash', 'ripple', 'eos', 'neo', 'aventus', 'qtum', 'eidoo']
            amount {[type]} -- [description]
            address {[type]} -- [description]

        Returns:
            [type] -- [description]
        '''
        url = '/account/withdraw'
        params = {
            'currency': currency,
            'quantity': amount,
            'address': address
        }

        result = self._get(url, params)

        self._debug('[get] withdraw: \n' + json.dumps(result, indent=2))
